﻿using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace Dsl.Ped.Editor.Helpers
{
    /// <summary>
    /// Helper methods for working with the XML 
    /// </summary>
    public class XmlHelper
    {
        /// <summary>Get the xmlns of the given XML file</summary>
        /// <param name="xmlDocument">The xml Document.</param>
        /// <returns>xmlns of the given <see cref="XmlDocument"/></returns>
        public static string GetXmlNamespace(XmlDocument xmlDocument)
        {
            return xmlDocument != null ? xmlDocument.DocumentElement.NamespaceURI : "";
        }

        /// <summary>
        /// Get the xmlns of the XML document of a given name
        /// </summary>
        /// <param name="fileName">Filename of the XML document</param>
        /// <returns>xmlns of the given XML file</returns>
        public static string GetXmlNamespace(string fileName)
        {
            var xmlDocument = GetXmlDocument(fileName);
            return GetXmlNamespace(xmlDocument);
        }

        /// <summary>
        /// Get the <see cref="XmlDocument"/> of a given fileName
        /// </summary>
        /// <param name="fileName">filename of the xml file</param>
        /// <returns><see cref="XmlDocument"/> of the given name, null if the required file doesn't exist or can't be loaded</returns>
        public static XmlDocument GetXmlDocument(string fileName)
        {
            var xmlFileContent = FileHelper.GetFileContent(fileName);
            if (string.IsNullOrEmpty(xmlFileContent))
            {
                return null;
            }

            var doc = new XmlDocument();
            doc.LoadXml(xmlFileContent);

            return doc;
        }

        /// <summary>
        /// Deserialize given xml file to the object of a given type
        /// </summary>
        /// <param name="objectType">Object type we want to deserialize the file to</param>
        /// <param name="xmlNamespace">Xml namespace of the Xml content</param>
        /// <param name="fileName">File name of the file to deserialize</param>
        /// <returns>Deserialized xml file, if the serialization was successfull, otherwise return null</returns>
        public static object DeserializeXmlFile(Type objectType, string xmlNamespace, string fileName)
        {
            var fileContent = FileHelper.GetFileContent(fileName);
            return fileContent == null ? null : DeserializeXmlContent(objectType, xmlNamespace, fileContent);
        }

        /// <summary>
        /// Deserialize given xml content to the object of a given type.
        /// </summary>
        /// <param name="objectType">Object type we want to deserialize the content to</param>
        /// <param name="xmlNamespace">Xml namespace of the Xml content</param>
        /// <param name="xmlFileContent">Content of the Xml file in a <see cref="string"/> format</param>
        /// <returns>Deserialized xml file content, if the serialization was successfull, otherwise returns null</returns>
        public static object DeserializeXmlContent(Type objectType, string xmlNamespace, string xmlFileContent)
        {
            // Projective type serializer
            var serializer = new XmlSerializer(objectType, xmlNamespace);

            try
            {
                object serializedObject;

                // Deserialize the xml file
                using (var reader = XmlReader.Create(new StringReader(xmlFileContent)))
                {
                    serializedObject = serializer.Deserialize(reader);
                }

                return serializedObject;
            } 
            catch (Exception exc)
            {
                throw new Exception("Unable to deserialize the Xml content: " + exc);
            }
        }

        /// <summary>
        /// Deserialize given xml content to the object of a given type using a XmlReader
        /// </summary>
        /// <param name="objectType">Object type we want to deserialize the content to</param>
        /// <param name="xmlNamespace">Xml namespace of the Xml content</param>
        /// <param name="xmlReader"><see cref="XmlReader"/> which may be used for deserialization</param>
        /// <returns>Deserialized xml file content, if the serialization was successfull, otherwise return null</returns>
        public static object DeserializeXmlContent(Type objectType, string xmlNamespace, XmlReader xmlReader)
        {
            // Projective type serializer
            var serializer = new XmlSerializer(objectType, xmlNamespace);

            try
            {
                object serializedObject;

                // Deserialize the xml file
                using (var reader = xmlReader)
                {
                    serializedObject = serializer.Deserialize(reader);
                }

                return serializedObject;
            }
            catch (Exception exc)
            {
                throw new Exception("Unable to deserialize the Xml content: " + exc);
            }
        }
    }
}
